home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / spreadsheet / Excel / Writer / BIFFwriter.php next >
PHP Script  |  2003-11-06  |  8KB  |  242 lines

  1. <?php
  2. /*
  3. *  Module written/ported by Xavier Noguer <xnoguer@php.net>
  4. *
  5. *  The majority of this is _NOT_ my code.  I simply ported it from the
  6. *  PERL Spreadsheet::WriteExcel module.
  7. *
  8. *  The author of the Spreadsheet::WriteExcel module is John McNamara 
  9. *  <jmcnamara@cpan.org>
  10. *
  11. *  I _DO_ maintain this code, and John McNamara has nothing to do with the
  12. *  porting of this code to PHP.  Any questions directly related to this
  13. *  class library should be directed to me.
  14. *
  15. *  License Information:
  16. *
  17. *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
  18. *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net
  19. *
  20. *    This library is free software; you can redistribute it and/or
  21. *    modify it under the terms of the GNU Lesser General Public
  22. *    License as published by the Free Software Foundation; either
  23. *    version 2.1 of the License, or (at your option) any later version.
  24. *
  25. *    This library is distributed in the hope that it will be useful,
  26. *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  28. *    Lesser General Public License for more details.
  29. *
  30. *    You should have received a copy of the GNU Lesser General Public
  31. *    License along with this library; if not, write to the Free Software
  32. *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  33. */
  34.  
  35. require_once('PEAR.php');
  36.  
  37. /**
  38. * Class for writing Excel BIFF records.
  39. * From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
  40. *
  41. * BIFF (BInary File Format) is the file format in which Excel documents are 
  42. * saved on disk.  A BIFF file is a complete description of an Excel document.
  43. * BIFF files consist of sequences of variable-length records. There are many 
  44. * different types of BIFF records.  For example, one record type describes a 
  45. * formula entered into a cell; one describes the size and location of a 
  46. * window into a document; another describes a picture format.
  47. *
  48. * @author   Xavier Noguer <xnoguer@php.net>
  49. * @category FileFormats
  50. * @package  Spreadsheet_Excel_Writer
  51. */
  52.  
  53. class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR
  54. {
  55.     /**
  56.     * The BIFF/Excel version (5). 
  57.     * @var integer
  58.     */
  59.     var $_BIFF_version = 0x0500;
  60.  
  61.     /**
  62.     * The byte order of this architecture. 0 => little endian, 1 => big endian 
  63.     * @var integer
  64.     */
  65.     var $_byte_order;
  66.  
  67.     /**
  68.     * The string containing the data of the BIFF stream
  69.     * @var string
  70.     */
  71.     var $_data;
  72.  
  73.     /**
  74.     * The size of the data in bytes. Should be the same as strlen($this->_data)
  75.     * @var integer
  76.     */
  77.     var $_datasize;
  78.  
  79.     /**
  80.     * The maximun length for a BIFF record. See _addContinue()
  81.     * @var integer
  82.     * @see _addContinue()
  83.     */
  84.     var $_limit;
  85.  
  86.     /**
  87.     * Constructor
  88.     *
  89.     * @access public
  90.     */
  91.     function Spreadsheet_Excel_Writer_BIFFwriter()
  92.     {
  93.         $this->_byte_order = '';
  94.         $this->_data       = '';
  95.         $this->_datasize   = 0;
  96.         $this->_limit      = 2080;   
  97.         // Set the byte order
  98.         $this->_setByteOrder();
  99.     }
  100.  
  101.     /**
  102.     * Determine the byte order and store it as class data to avoid
  103.     * recalculating it for each call to new().
  104.     *
  105.     * @access private
  106.     */
  107.     function _setByteOrder()
  108.     {
  109.         // Check if "pack" gives the required IEEE 64bit float
  110.         $teststr = pack("d", 1.2345);
  111.         $number  = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
  112.         if ($number == $teststr) {
  113.             $byte_order = 0;    // Little Endian
  114.         }
  115.         elseif ($number == strrev($teststr)){
  116.             $byte_order = 1;    // Big Endian
  117.         }
  118.         else {
  119.             // Give up. I'll fix this in a later version.
  120.             return $this->raiseError("Required floating point format ".
  121.                                      "not supported on this platform.");
  122.         }
  123.         $this->_byte_order = $byte_order;
  124.     }
  125.  
  126.     /**
  127.     * General storage function
  128.     *
  129.     * @param string $data binary data to prepend
  130.     * @access private
  131.     */
  132.     function _prepend($data)
  133.     {
  134.         if (strlen($data) > $this->_limit) {
  135.             $data = $this->_addContinue($data);
  136.         }
  137.         $this->_data      = $data.$this->_data;
  138.         $this->_datasize += strlen($data);
  139.     }
  140.  
  141.     /**
  142.     * General storage function
  143.     *
  144.     * @param string $data binary data to append
  145.     * @access private
  146.     */
  147.     function _append($data)
  148.     {
  149.         if (strlen($data) > $this->_limit) {
  150.             $data = $this->_addContinue($data);
  151.         }
  152.         $this->_data      = $this->_data.$data;
  153.         $this->_datasize += strlen($data);
  154.     }
  155.  
  156.     /**
  157.     * Writes Excel BOF record to indicate the beginning of a stream or
  158.     * sub-stream in the BIFF file.
  159.     *
  160.     * @param  integer $type Type of BIFF file to write: 0x0005 Workbook,
  161.     *                       0x0010 Worksheet.
  162.     * @access private
  163.     */
  164.     function _storeBof($type)
  165.     {
  166.         $record  = 0x0809;        // Record identifier
  167.  
  168.         // According to the SDK $build and $year should be set to zero.
  169.         // However, this throws a warning in Excel 5. So, use magic numbers.
  170.         if ($this->_BIFF_version == 0x0500) {
  171.             $length  = 0x0008;
  172.             $unknown = '';
  173.             $build   = 0x096C;
  174.             $year    = 0x07C9;
  175.         }
  176.         elseif ($this->_BIFF_version == 0x0600) {
  177.             $length  = 0x0010;
  178.             $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8
  179.             $build   = 0x0DBB;
  180.             $year    = 0x07CC;
  181.         }
  182.         $version = $this->_BIFF_version;
  183.    
  184.         $header  = pack("vv",   $record, $length);
  185.         $data    = pack("vvvv", $version, $type, $build, $year);
  186.         $this->_prepend($header.$data.$unknown);
  187.     }
  188.  
  189.     /**
  190.     * Writes Excel EOF record to indicate the end of a BIFF stream.
  191.     *
  192.     * @access private
  193.     */
  194.     function _storeEof() 
  195.     {
  196.         $record    = 0x000A;   // Record identifier
  197.         $length    = 0x0000;   // Number of bytes to follow
  198.         $header    = pack("vv", $record, $length);
  199.         $this->_append($header);
  200.     }
  201.  
  202.     /**
  203.     * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
  204.     * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
  205.     * must be split up into CONTINUE blocks.
  206.     *
  207.     * This function takes a long BIFF record and inserts CONTINUE records as
  208.     * necessary.
  209.     *
  210.     * @param  string  $data The original binary data to be written
  211.     * @return string        A very convenient string of continue blocks
  212.     * @access private
  213.     */
  214.     function _addContinue($data)
  215.     {
  216.         $limit      = $this->_limit;
  217.         $record     = 0x003C;         // Record identifier
  218.  
  219.         // The first 2080/8224 bytes remain intact. However, we have to change
  220.         // the length field of the record.
  221.         $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
  222.         
  223.         $header = pack("vv", $record, $limit);  // Headers for continue records
  224.  
  225.         // Retrieve chunks of 2080/8224 bytes +4 for the header.
  226.         for($i = $limit; $i < strlen($data) - $limit; $i += $limit)
  227.         {
  228.             $tmp .= $header;
  229.             $tmp .= substr($data, $i, $limit);
  230.         }
  231.  
  232.         // Retrieve the last chunk of data
  233.         $header  = pack("vv", $record, strlen($data) - $i);
  234.         $tmp    .= $header;
  235.         $tmp    .= substr($data,$i,strlen($data) - $i);
  236.  
  237.         return $tmp;
  238.     }
  239. }
  240. ?>
  241.